package com.artconcurrency.chapter4;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName com.artconcurrency.chapter4
 * Description: <类功能描述>. <br>
 * <p>
 * <使用说明>
 * </p>
 * @Author tree
 * @Date 2019-05-01 18:58
 * @Version 1.0
 */
public class SynchronizeTest {
    public static void main(String[] args) {
        int poolSize =100;
        ExecutorService executorService =  Executors.newFixedThreadPool(poolSize);
        SynchronnizeDemo shareDemo = new SynchronnizeDemo();
        Account account = new Account("lzs", 100);
        for (int i = 0; i <poolSize; i++) {
//            executorService.execute(new Thread(()->{
////                new SynchronnizeDemo().m4();
//                shareDemo.m4();
//            }));
            executorService.execute(new AccountOperator(account));
        }

    }

}

class SynchronnizeDemo {
    static Object a = 1;

    /**
     * 同一个实例／不同实例都可以同时执行该方法
     */
    public void m1() {
        System.out.println("entering public method, sleep 2s");
        SleepUtils.second(2);
        System.out.println("entered public method");
    }


    /**
     * 不同实例可以同时进入
     * 同一实例被阻塞
     */
    public  synchronized void m2() {
        System.out.println("entering public  synchronized method， sleep 2s");
        SleepUtils.second(2);
        System.out.println("entered public synchronized method");

    }
    /**
     * 不同实例可以同时进入
     * 同一实例被阻塞
     */
    public static synchronized void m3() {
        System.out.println("thread："+Thread.currentThread().getName()+", entering public static synchronized method， sleep 2s");
        SleepUtils.second(2);
        System.out.println("thread："+Thread.currentThread().getName()+", entered public static synchronized method");
    }


    /**
     * 不同实例可以同时进入
     * 同一实例被阻塞
     */
    public  void m4() {
        synchronized (this) {
            System.out.println("thread："+Thread.currentThread().getName()+", entering synchronized block， sleep 2s");
            SleepUtils.second(2);
            System.out.println("thread："+Thread.currentThread().getName()+", entered  synchronized block");
        }
    }

    public  void m5() {
        synchronized (a) {
            System.out.println("public synchronized(this) method");
        }
    }

}



class SynchronizeOperator implements Runnable{
    private SynchronnizeDemo synchronnizeDemo;

    public SynchronizeOperator(SynchronnizeDemo synchronnizeDemo) {
        this.synchronnizeDemo = synchronnizeDemo;
    }

    @Override
    public void run() {
        synchronized (synchronnizeDemo){
        }
    }
}

/**
 * 账户类
 *
 */
@AllArgsConstructor
@Data
class Account{
    private String name;
    private float amount;



    public void deposit(float amount){
        this.amount+= amount;
        SleepUtils.second(1);
    }

    public void withdraw(float amount){
        this.amount -= amount;
        SleepUtils.second(1);
    }

    public float getBalance(){
        return amount;
    }

}

/**
 *
 */
@AllArgsConstructor
class AccountOperator implements Runnable{
    private Account account;

    @Override
    public void run() {
        synchronized (account){
            account.deposit(100);
            account.withdraw(50);
            System.out.println(Thread.currentThread().getName()+", amount = "+account.getAmount());
        }
    }
}

class AccountFieldOperator implements Runnable{
    private byte[] lock = new byte[0];

    @Override
    public void run() {
        synchronized (lock){
//            account.deposit(100);
//            account.withdraw(50);
//            System.out.println(Thread.currentThread().getName()+", amount = "+account.getAmount());
        }
    }
}

@AllArgsConstructor
class AccountThisOperator implements Runnable{
    private Account account;

    @Override
    public void run() {
        synchronized (account){
            account.deposit(100);
            account.withdraw(50);
            System.out.println(Thread.currentThread().getName()+", amount = "+account.getAmount());
        }
    }
}
